package cn.com.infohold.smartcity.api;

import android.support.annotation.Keep;

import org.greenrobot.eventbus.EventBus;

import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import library.http.Hook;
import library.http.HttpCallback;
import library.http.HttpTask;
import library.http.HttpUtils;
import library.image.BitmapOption;
import library.image.ImageUtils;

/**
 * Created by apple on 2017/5/16.
 */
@Keep
public class HttpHook<T> extends Hook<T> {
    protected HttpHook(HttpTask task) {
        super(task);
    }

    public BitmapOption image() {
        return image(null);
    }

    public BitmapOption image(Object tag) {
        return ImageUtils.obtain(HttpUtils.getContext())
                .tag(tag)
                .httpTask(getHttpTask());
    }

    public Observable<T> observable() {
        Observable<T> observable = Observable.just(getHttpTask())
                .subscribeOn(Schedulers.io())
                .map(new Function<HttpTask, T>() {
                    @Override
                    public T apply(@NonNull HttpTask task) throws Exception {
                        Object result = task.execute();
                        if (result instanceof Throwable) {
                            throw new Exception("url : " + task.getUrl(), (Throwable) result);
                        } else {
                            return (T) result;
                        }
                    }
                })
                .doOnError(new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {

                    }
                })
                .subscribeOn(AndroidSchedulers.mainThread());
        return observable;
    }

    public Flowable<T> flowable() {
        Flowable<T> flowable = Flowable.just(getHttpTask())
                .subscribeOn(Schedulers.io())
                .map(new Function<HttpTask, T>() {
                    @Override
                    public T apply(@NonNull HttpTask task) throws Exception {
                        Object result = task.execute();
                        if (result instanceof Throwable) {
                            throw new Exception("url : " + task.getUrl(), (Throwable) result);
                        } else {
                            return (T) result;
                        }
                    }
                })
                .doOnError(new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {

                    }
                })
                .subscribeOn(AndroidSchedulers.mainThread());
        return flowable;
    }

    public void postEvent() {
        postEvent(null);
    }

    public void postEvent(Integer requestCode) {
        getHttpTask().callback(new PostCallback<T, Integer>(requestCode) {

            private void fireEvent(int ret, Throwable e) {
                if (getTag() != null) {
                    HttpEvent<T> event = new HttpEvent<T>(getTag(), ret, null);
                    event.setError(e);
                    EventBus.getDefault().post(event);
                } else {
                    EventBus.getDefault().post(e);
                }
            }

            private void fireEvent(int ret, T data) {
                if (getTag() != null) {
                    HttpEvent<T> event = new HttpEvent<T>(getTag(), ret, data);
                    EventBus.getDefault().post(event);
                } else {
                    EventBus.getDefault().post(data);
                }
            }

            @Override
            protected void onStart() {
                super.onStart();
            }

            @Override
            protected void onCancel() {
                super.onCancel();
                fireEvent(HttpEvent.STATE_CANCEL, (Exception) null);
            }

            @Override
            protected void onTimeout(Exception e) {
                super.onTimeout(e);
                fireEvent(HttpEvent.STATE_TIMEOUT, e);
            }

            @Override
            protected void onSuccess(T data) {
                super.onSuccess(data);
                fireEvent(HttpEvent.STATE_SUCCESS, data);
            }

            @Override
            protected void onFailure(Exception e) {
                super.onFailure(e);
                fireEvent(HttpEvent.STATE_FAILURE, e);
            }

            @Override
            protected void onFinish() {
                super.onFinish();
            }
        });

    }


    private static class PostCallback<Result, Tag> extends HttpCallback<Result> {
        private Tag tag;

        protected PostCallback(Tag tag) {
            this.tag = tag;
        }

        protected Tag getTag() {
            return tag;
        }
    }

}
